package org.mengyun.tcctransaction.sample.dubbo.order.service;

import org.apache.commons.lang3.tuple.Pair;
import org.mengyun.tcctransaction.CancellingException;
import org.mengyun.tcctransaction.ConfirmingException;
import org.mengyun.tcctransaction.sample.dubbo.order.domain.entity.Order;
import org.mengyun.tcctransaction.sample.dubbo.order.domain.entity.Shop;
import org.mengyun.tcctransaction.sample.dubbo.order.domain.repository.ShopRepository;
import org.mengyun.tcctransaction.sample.dubbo.order.domain.service.OrderServiceImpl;
import org.mengyun.tcctransaction.sample.dubbo.order.domain.service.PaymentServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;

/**
 * Created by changming.xie on 4/1/16.
 */
@Service
public class PlaceOrderServiceImpl {

    private static final Logger logger = LoggerFactory.getLogger(PlaceOrderServiceImpl.class);

    @Autowired
    ShopRepository shopRepository;

    @Autowired
    OrderServiceImpl orderService;

    @Autowired
    PaymentServiceImpl paymentService;

    /**
     * 下单：
     * 1. 查询商家。需要获取商家的ownerUserId。
     * 2. 创建订单。创建订单时ord_order只存了支付关系相关的数据，资金（payamount）相关的还没有。
     * 3. 付款。
     */
    public String placeOrder(long payerUserId, long shopId, List<Pair<Long, Integer>> productQuantities, BigDecimal redPacketPayAmount) {
        Shop shop = shopRepository.findById(shopId);

        Order order = orderService.createOrder(payerUserId, shop.getOwnerUserId(), productQuantities);

        Boolean result = false;

        try {
            // 注意：这里第2,3个参数分别是红包支付金额和资金账户支付金额。而且还要看一下order.getTotalAmount()，不是简单的贫血模型哦！
            // 实际的逻辑是，支付金额（额定总价） =  红包支出金额（WEB上填写的） + 资金帐户支出金额（这里是用额定总价减去红包支出金额）
            paymentService.makePayment(order, redPacketPayAmount, order.getTotalAmount().subtract(redPacketPayAmount));
            // TODO -WK -ASK 在实践中，三个CATCH分别要做什么？

            result = true;

        } catch (ConfirmingException confirmingException) {
            logger.error("Find ConfirmingException: " + confirmingException.getMessage());
            // exception throws with the tcc transaction status is CONFIRMING,
            // when tcc transaction is confirming status,
            // the tcc transaction recovery will try to confirm the whole transaction to ensure eventually consistent.

        } catch (CancellingException cancellingException) {
            logger.error("Find CancellingException: " + cancellingException.getMessage());
            // exception throws with the tcc transaction status is CANCELLING,
            // when tcc transaction is under CANCELLING status,
            // the tcc transaction recovery will try to cancel the whole transaction to ensure eventually consistent.
        } catch (Throwable e) {
            logger.error("Find Throwable: " + e.getMessage());
            // other exceptions throws at TRYING stage.
            // you can retry or cancel the operation.
            e.printStackTrace();
        }

        return order.getMerchantOrderNo();
    }
}
